#include <mm.h>
#include <process.h>
#include <kernel.h>
#include <string.h>
#include <list.h>

/**
 * @brief mem_flag
 * 描述一块内存
 */
struct mem_flag {
    uint16_t maigc;
    mem_t next;
};
/**
 * @brief 动态内存
 * _start:起始地址 - 需要页对齐
 * _end:结束地址
 * _start_fpage:第一块空闲页的地址
 * pfree_page:指向一块空闲的页首地址
 * bit_pags:位图占的页数目
 * free_pages_nr:空闲页的总数
 */
static struct dynamic_mem {
    mem_t _start;
    mem_t _end;
    mem_t free_page_list;
    uint32_t free_pages_nr, pages;
} dmem_regions [region_count] = {0};
/**
 * @brief dynamic_mem_init
 * 初始化一块动态内存
 * @param pmem
 */
int dynamic_mem_init(struct dynamic_mem *pmem, mem_t _start, mem_t _end)
{
    mem_t start = PAGE_ENTRY(_start);
    mem_t end = PAGE_FRON(_end);
    struct dynamic_mem *pdmem = dmem_regions;
    register mem_t count;
    struct mem_flag *p;
    if(start >= end)
        return;
    while (pdmem < &dmem_regions[region_count])
    {
        if(MEM_CHECK(pdmem->_start, start, pdmem->_end) ||
            MEM_CHECK(pdmem->_start, end, pdmem->_end))
            return -EMBOUND;
        ++pdmem;
    }
    for( p = count = start; count <= end;){
        p->maigc = PAGE_MAGIC;
        p = p->next = count += PAGE_SIZE;
    }
    p->next = NULL;
    pmem->free_page_list = start;
    pmem->_start = start;
    pmem->_end = end;
    pmem->free_pages_nr = pmem->pages = (end - start)>>PAGE_SHIFT + 1;
}
void dmem_init(uint32_t index, mem_t start, mem_t end)
{
    dynamic_mem_init(&dmem_regions[index], start, end);
}
/**
 * @brief __get_free_page
 * 从一个动态内存中分配一块页
 * @param pmem : 动态内存的指针
 * @return mem_t : 返回页的首地址
 */
mem_t _get_free_page(struct dynamic_mem *pmem)
{
    mem_t ret;
    struct mem_flag *p;
    if(!pmem)
        return 0;
    ret = p = pmem->free_page_list;
    if(p->maigc != PAGE_MAGIC)
        return 0;
    pmem->free_page_list = p->next;
    --pmem->free_pages_nr;
    memset(p, 0, sizeof(struct mem_flag));
    return ret;
}
/**
 * @brief _free_page
 * 
 * @param page 
 * @return int 
 */
int _free_page(void* page)
{
    struct mem_flag *p = PAGE_ENTRY((mem_t)page);
    if(p->maigc == PAGE_MAGIC)
        return -EFPAGE;
    p->maigc = PAGE_MAGIC;
    if(MEM_CHECK(dmem_regions[kernel_region]._start, (mem_t)page, dmem_regions[kernel_region]._end))
        goto _kernel_region;
    else
        goto _user_region;

_user_region:
    p->next = dmem_regions[user_region].free_page_list;
    dmem_regions[user_region].free_page_list = (mem_t)p;
    return 0;
_kernel_region:
    p->next = dmem_regions[kernel_region].free_page_list;
    dmem_regions[kernel_region].free_page_list = (mem_t)p;
    return 0;
}
/**
 * @brief kmem_mannager
 * 小内存分配系统
 */
#define KMEM_CHECK(addr)    (addr >= &kmem_mannager[0] && addr <= &kmem_mannager[7])
#define INIT_KCACHE(size) {size, {NULL}, {NULL}}
struct kmem_cache {
    uint32_t block_size;
    mem_t free_block_list;
    struct list_head manager_list;
} kmem_mannager[] = {
    INIT_KCACHE(32),
    INIT_KCACHE(64),
    INIT_KCACHE(128),
    INIT_KCACHE(256),
    INIT_KCACHE(512),
    INIT_KCACHE(1024),
    INIT_KCACHE(2048),
    INIT_KCACHE(4096),
    INIT_KCACHE(0),
};
struct mem_block {
    struct kmem_cache* parent;
    mem_t next;
    uint32_t maigc;
};
/**
 * @brief _kmem_cache_init
 * 
 */
static void _kmem_cache_init(struct kmem_cache*kcache)
{
    register mem_t size = kcache->block_size;
    register mem_t start = _get_free_page(&dmem_regions[kernel_region]);
    register mem_t end = start + PAGE_SIZE;
    struct mem_block *pflag = start;

    for(; start < end;){
        pflag->maigc = BLOCK_MAGIC;
        pflag->parent = kcache;
        pflag = pflag->next = start+=size;
    }
    kcache->free_block_list = end - PAGE_SIZE;
}
/**
 * @brief page_init
 * 初始化内存管理器
 * @param page_base 
 */
void kmem_mannager_init(void)
{
    struct kmem_cache *pcache = kmem_mannager;
    while (pcache->block_size != 0)
    {
        _kmem_cache_init(pcache);
        pcache++;
    }
}
/**
 * @brief Get the order object
 * 
 * @param size 
 * @return int32_t 
 */
int32_t get_order(uint32_t size)
{
    uint32_t real_size = size + sizeof(mem_t);
    struct kmem_cache *pcache = kmem_mannager;
    register uint32_t ret = 0;
    for(;(pcache->block_size) < real_size;++pcache,++ret);
    return ret;
}
/**
 * @brief kmalloc
 * @param size 
 * @param priority 
 * @return void* 
 */
void* kmalloc(uint32_t size)
{
    struct mem_block *ret;
    if(size > 4095)
        return NULL;
    uint32_t order = get_order(size);

    ret = kmem_mannager[order].free_block_list;
    kmem_mannager[order].free_block_list = ret->next;
    return (void*)&ret->next;
}
/**
 * @brief free
 * 
 * @param ptr 
 */
void free(void *ptr)
{
    struct mem_block *pmem = container_of(next, struct mem_block, ptr);
    struct kmem_cache *pcache = pmem->parent;
    if(!KMEM_CHECK(pcache)){
        printk("error parent %x\n",pcache);
        return;
    }
    pmem->maigc = BLOCK_MAGIC;
    pmem->next = pcache->free_block_list;
    pcache->free_block_list = pmem;
}